/*
 *  arch/arm/include/asm/mmu_context.h
 *
 *  Copyright (C) 1996 Russell King.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 *  Changelog:
 *   27-06-1996	RMK	Created
 */
#ifndef __ASM_ARM_MMU_CONTEXT_H
#define __ASM_ARM_MMU_CONTEXT_H

#include <linux/sched.h>
#include <asm/memory.h>
#include <asm/tlbflush.h>

// #define cpu_do_switch_mm		__cpu_fn(CPU_NAME,_switch_mm)
#define cpu_do_switch_mm		cpu_v7_switch_mm
#define cpu_switch_mm(pgd,mm) cpu_do_switch_mm(virt_to_phys(pgd),mm)

#define cpu_get_pgd()	\
	({						\
		unsigned long pg;			\
		__asm__("mrc	p15, 0, %0, c2, c0, 0"	\
			 : "=r" (pg) : : "cc");		\
		pg &= ~0x3fff;				\
		(pgd_t *)phys_to_virt(pg);		\
	})

#define ASID_BITS		8
#define ASID_MASK		((~0) << ASID_BITS)
#define ASID_FIRST_VERSION	(1 << ASID_BITS)

extern unsigned int cpu_last_asid;

void __init_new_context(struct task_struct *tsk, struct mm_struct *mm);
void __new_context(struct mm_struct *mm);

#define init_new_context(tsk,mm)	(__init_new_context(tsk,mm),0)

static inline void check_context(struct mm_struct *mm)
{
	// printf("this is %s(): %d\r\n", __func__, __LINE__);

	if ((mm->context.id ^ cpu_last_asid) >> ASID_BITS) {
		// printf("this is %s(): %d\r\n", __func__, __LINE__);
		__new_context(mm);
	}

	// if (unlikely(mm->context.kvm_seq != init_mm.context.kvm_seq))
	// 	__check_kvm_seq(mm);
}

/*
 * This is the actual mm switch as far as the scheduler
 * is concerned.  No registers are touched.  We avoid
 * calling the CPU specific function when the mm hasn't
 * actually changed.
 */
static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
	  struct task_struct *tsk)
{
	// printf("this is %s(): %d\r\n", __func__, __LINE__);
// #ifdef CONFIG_MMU
// 	unsigned int cpu = smp_processor_id();

// #ifdef CONFIG_SMP
// 	/* check for possible thread migration */
// 	if (!cpumask_empty(mm_cpumask(next)) &&
// 	    !cpumask_test_cpu(cpu, mm_cpumask(next)))
// 		__flush_icache_all();
// #endif
// 	if (!cpumask_test_and_set_cpu(cpu, mm_cpumask(next)) || prev != next) {
		check_context(next);
		cpu_switch_mm(next->pgd, next);
// 		if (cache_is_vivt())
// 			cpumask_clear_cpu(cpu, mm_cpumask(prev));
// 	}
// #endif
	// printf("this is %s(): %d\r\n", __func__, __LINE__);
}

#define activate_mm(prev,next)	switch_mm(prev, next, NULL)

#endif
